package com.dcivision.workflow.core;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.Utility;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;

/**
 * check the condition of step operation(add/delete/edit/move)
 * @author TC.tang
 * @createDate 2007-2-8
 */
public class WorkflowOperationCheckManager {

  private SessionContainer sessionCon = null;
  private Connection conn = null;
  
  public WorkflowOperationCheckManager(SessionContainer sessionCon,Connection conn){
    this.sessionCon = sessionCon;
    this.conn = conn;
  }
  public boolean checkIfCanDeleteAllStepsAfterCurrentStep(Integer stepID){
    //0.select all steps after this currentStep
    //1.check if any other step whose actionTaker relate to those delete steps
    //empty
    return false;
  }
  /**
   * 
   * @param workflowRecordID
   * @return
   * @throws ApplicationException
   */
  public boolean checkIfDeleteAllStepsAfterCurrentStepSuccessfull(Integer workflowRecordID) throws ApplicationException{
    //0.select all step
    //1.check all special step which relate to some step can get the step record
    //2.if can not get the record,throw exception
    if(!canGetTheStepRecordWhichSomeSpecialActionTakerRelateToByWorkflowRecordID(workflowRecordID)){
      throw new ApplicationException("errors.workflow.someStep_actionTaker_relateTo_can_not_delete");
    }
    return true;
  }
  /**
   * 
   * @param stepID
   * @return
   * @throws ApplicationException
   */
  public boolean checkIfCanDeleteCurrentStep(Integer stepID) throws ApplicationException{
    if(haveSomeStepWhoseActionTakerRelateToCurrentStep(stepID)){
      //have some step whose actionTaker relate to this step which will delete
      //throw exception here 
      throw new ApplicationException("errors.workflow.someStep_actionTaker_relateTo_can_not_delete");
    }
    return true;
  }
  /**
   * 
   * @param workflowStepID
   * @return
   * @throws ApplicationException
   */
  public boolean checkIfMoveSingleStepSuccessfull(Integer workflowStepID) throws ApplicationException{
    //0.check if any step that connect to this step still in his childTree
    if(!checkIfAnyStepThatConnectToCurrentStepStillInTheChildTree(workflowStepID)){
      //throw exception here
      throw new ApplicationException("errors.workflow.someStep_actionTaker_relateTo_can_not_move");
    }
    //1.check if any step which this step connect to still in his parentTree
    if(!checkIfAnyStepWhichCurrentStepConnectToStillInTheParentTree(workflowStepID)){
      //throw exception here
      throw new ApplicationException("errors.workflow.someStep_actionTaker_relateTo_can_not_move");
    }
    return true;
  }
  
  private boolean haveSomeStepWhoseActionTakerRelateToCurrentStep(Integer stepID) throws ApplicationException{
    MtmWorkflowStepUserActorDAObject userActorDAO = new MtmWorkflowStepUserActorDAObject(this.sessionCon,this.conn);
    Integer reportOfActionTakerCount = userActorDAO.getListCountByActorIDAndActorTypeAndPermissions(stepID,MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER,null);
    if(!Utility.isEmpty(reportOfActionTakerCount)&&reportOfActionTakerCount.intValue()>0){
      return true;//have some step whose actionTaker relate to currentStep's actionTaker
    }
    Integer actionTakerCount = userActorDAO.getListCountByActorIDAndActorTypeAndPermissions(stepID,MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER,null);
    if(!Utility.isEmpty(actionTakerCount)&&actionTakerCount.intValue()>0){
      return true;//have some step whose actionTaker relate to currentStep's actionTaker
    }
    return false;//havent
  }
  
  private boolean canGetTheStepRecordWhichSomeSpecialActionTakerRelateToByWorkflowRecordID(Integer workflowRecordID) throws ApplicationException{
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(this.sessionCon,this.conn);
    MtmWorkflowStepUserActorDAObject userActorDAO = new MtmWorkflowStepUserActorDAObject(this.sessionCon,this.conn);
    List allStepList = stepDAO.getListByWorkflowRecordID(workflowRecordID);
    for(Iterator it=allStepList.iterator();it.hasNext();){
      WorkflowStep step = (WorkflowStep)it.next();
      if(!buildTheWorkflowStepActionTakerByActorType(userActorDAO,stepDAO,step)){
        return false;
      } 
    }
    
    return true;
  }
  
  private boolean buildTheWorkflowStepActionTakerByActorType(MtmWorkflowStepUserActorDAObject userActorDAO,WorkflowStepDAObject stepDAO,WorkflowStep step) throws ApplicationException{
    if(!buildTheReportOfActionTaker(userActorDAO,stepDAO,step.getID())){
      return false;
    }
    
    if(!buildTheActionTaker(userActorDAO,stepDAO,step.getID())){
      return false;
    }
    
    return true;
  }
  private boolean buildTheReportOfActionTaker(MtmWorkflowStepUserActorDAObject userActorDAO,WorkflowStepDAObject stepDAO,Integer workflowStepID) throws ApplicationException{
    List actionTakerList = userActorDAO.getListByWorkflowStepIDAndActorType(workflowStepID, MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER);
    
    for(Iterator it=actionTakerList.iterator();it.hasNext();){
      MtmWorkflowStepUserActor tmpStepActor = (MtmWorkflowStepUserActor)it.next();
      try{
        stepDAO.getObjectByID(tmpStepActor.getActorID());
      }catch(Exception ex){
        return false;//catch this exception :means can't get this record
      }
    }
    return true;
  }
  
  private boolean buildTheActionTaker(MtmWorkflowStepUserActorDAObject userActorDAO,WorkflowStepDAObject stepDAO,Integer workflowStepID) throws ApplicationException{
    List actionTakerList = userActorDAO.getListByWorkflowStepIDAndActorType(workflowStepID, MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER);
    
    for(Iterator it=actionTakerList.iterator();it.hasNext();){
      MtmWorkflowStepUserActor tmpStepActor = (MtmWorkflowStepUserActor)it.next();
      try{
        stepDAO.getObjectByID(tmpStepActor.getActorID());
      }catch(Exception ex){
        return false;//catch this exception :means can't get this record
      }
    }
    return true;
  }
  
  /**
   * 
   * @param currentStepID
   * @return
   * @throws ApplicationException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   * @throws NoSuchMethodException
   */
  private boolean checkIfAnyStepThatConnectToCurrentStepStillInTheChildTree(Integer currentStepID) throws ApplicationException{
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(this.sessionCon,this.conn);
    WorkflowRetrievalManager retrievalManager = new WorkflowRetrievalManager(this.sessionCon,this.conn);
     
    String[] selectItem = new String[]{"ID"};
    Map parameterMap = new HashMap();
    parameterMap.put("ACTOR_ID", new Object[]{currentStepID});
    parameterMap.put("ACTOR_TYPE",new Object[]{MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER,MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER});
    List relateStepIDList = stepActorDAO.getListByParametersAndPermissions(selectItem, parameterMap, null);
    
    for(Iterator it=relateStepIDList.iterator();it.hasNext();){
      Map relateStepID = (Map)it.next();
      List superStepList = new ArrayList();
      List superStepIDList = null;
      superStepList = retrievalManager.getSuperStepList(Integer.valueOf((String)relateStepID.get("ID")), superStepList);
      try {
        superStepIDList = Utility.getPropertyList(superStepList, "ID");
      } catch(Exception ex){
        throw new ApplicationException("errors.framework.fatal_error");
      }
      if(!superStepIDList.contains(currentStepID)){
        return false;
      } 
    }
    return true;
  }
  
  private boolean checkIfAnyStepWhichCurrentStepConnectToStillInTheParentTree(Integer currentStepID) throws ApplicationException{
    MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(this.sessionCon,this.conn);
    WorkflowRetrievalManager retrievalManager = new WorkflowRetrievalManager(this.sessionCon,this.conn);
     
    String[] selectItem = new String[]{"ACTOR_ID"};
    Map parameterMap = new HashMap();
    parameterMap.put("WORKFLOW_STEP_ID", new Object[]{currentStepID});
    parameterMap.put("ACTOR_TYPE",new Object[]{MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER,MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER});
    List relateStepIDList = stepActorDAO.getListByParametersAndPermissions(selectItem, parameterMap, null);
    List superStepList = new ArrayList();
    List superStepIDList = null;
    superStepList = retrievalManager.getSuperStepList(currentStepID, superStepList);
    try {
      superStepIDList = Utility.getPropertyList(superStepList, "ID");
    } catch(Exception ex){
      throw new ApplicationException("errors.framework.fatal_error");
    }
    
    for(Iterator it=relateStepIDList.iterator();it.hasNext();){
      Map relateStepID = (Map)it.next();
      if(!superStepIDList.contains(Integer.valueOf((String)relateStepID.get("ACTOR_ID")))){
        return false;
      } 
    }
    return true;
  }
}
